﻿/* Botón con cambio de color por transformación de color
 *
 * clase rápida dependiente del proyecto
 * nivel: script externalizado
 */

import caurina.transitions.Tweener;
import flash.geom.ColorTransform;

class CambioColor extends MovieClip {
	var color_apagado:ColorTransform;
	var color_resaltado:ColorTransform;
	var color_encendido:ColorTransform;
	var encendido:Boolean;

	public static function wrap(ref:MovieClip):MovieClip {
		new CambioColor(ref);
		return ref;
	}
	
	function CambioColor(ref:MovieClip) {
		trace("CambioColor: " + ref);
		ref.resaltar = resaltar;
		ref.desresaltar = desresaltar;
		ref.encender = encender;
		ref.apagar = apagar;
		ref.transicion = transicion;
		ref.velocidad = velocidad;
		ref.addProperty("__color", get_color, set_color);
		ref.encendido = false;
		ref.color_apagado = new ColorTransform();
		ref.color_resaltado = new ColorTransform();
		ref.color_encendido = new ColorTransform();
		ref.set_color_apagado = set_color_apagado;
		ref.set_color_encendido = set_color_encendido;
		ref.set_color_resaltado = set_color_resaltado;
	}

	public function set_color_apagado(color:Number):Void {
		color_apagado.rgb = color;
	}
	
	public function set_color_encendido(color:Number):Void {
		color_encendido.rgb = color;
	}
	
	public function set_color_resaltado(color:Number):Void {
		color_resaltado.rgb = color;
	}	
	function resaltar() {
		//trace("CambioColor.resaltar: " + texto_resaltado);
		if(!encendido) {
			transicion(color_resaltado);
		}
	}

	function desresaltar() {
		if(!encendido) {
			transicion(color_apagado);
		}
	}
	
	function encender() {
		encendido = true;
		transicion(color_encendido);
	}
	
	function apagar() {
		encendido = false;
		transicion(color_apagado);
	}
	
	private var velocidad:Number = 600;   // unidad de medida: [unidades de color/segundo]
	private var direccion, punto:Array;
	private var _color_temp:Number;
	
	/* Parametrización de un intervalo entre 2 puntos (x, y z) en función de
	 * un parámetro en el intervalo [0..1], en el sentido de que los puntos en el
	 * intervalo [punto_0=(x0, y0, z0)..punto_1=(x1, y1, z1)] sean en función del intervalo [0..1]
	 */
	private function transicion(color_final:ColorTransform):Void {
		var d_1, d, t:Number;
		var color_1, color_0:ColorTransform;

		//Tweener.removeTweens(this);
		
		color_1 = color_final;
		color_0 = transform.colorTransform;
		
		// 0. Guardar el punto actual (x, y, z)
		punto = [color_0.redOffset, color_0.greenOffset, color_0.blueOffset];
		
		// 1. cálculo de la distancia d entre
		// color_0 = transform.ColorTransform y color_1 = color_final (color_{encendido|apagado|resaltado})
		d_1 = Math.sqrt( (color_1.redOffset-color_0.redOffset)*(color_1.redOffset-color_0.redOffset) + (color_1.greenOffset-color_0.greenOffset)*(color_1.greenOffset-color_0.greenOffset) );
		d = Math.sqrt( d_1*d_1 + (color_1.blueOffset-color_0.blueOffset)*(color_1.blueOffset-color_0.blueOffset) );
		
		trace("CambioColor.transicion, d: " + d + ", velocidad: " +velocidad+ ".");
		
		// 2. cálculo del tiempo t = f(d), el tiempo es en función de la distancia
		t = d / velocidad;
		
		// 3. cálculo del vector dirección, tal que proyecte el intervalo [0, 1] en todos los puntos desde color_0 hasta color_1,
		// intervalo[0..1]* vector dirección = intervalo[vector[0, 0, 0]..vector[x1-x0, y1-y0, z1-z0]]
		// Como caso excepcional, si vector[x1-x0, y1-y0, z1-z0] = vector[0, 0, 0] entonces este vector[0, 0, 0] se proyecta en todo el intervalo [0..1]
		direccion = [color_1.redOffset-color_0.redOffset, color_1.greenOffset-color_0.greenOffset, color_1.blueOffset-color_0.blueOffset];
		
		// 4. invocar a Tweener
		var autoref:MovieClip = this;
		autoref.__color = 0;
		_color_temp = 0;
		Tweener.addTween(this, {__color: 1, delay: 0, time: t, transition: "linear"});
	}
	
	/* Realiza la proyección inversa del parámetro color como se explica en el
	 * cálculo del vector dirección, y aplica el color resultante
	 *
	 * parám. color: un número en el intervalo [0,1], que representa una proyección
	 * como se explica en el cálculo del vector dirección
	 */
	private function set_color(color:Number):Void {
		var colorTr:ColorTransform = new ColorTransform(0,0,0,1,color*direccion[0]+punto[0],color*direccion[1]+punto[1],color*direccion[2]+punto[2],0);		
		this.transform.colorTransform = colorTr;
		_color_temp = color;
	}
	
	/* Devuelve el color asignado (R, G, B), proyectado en el intervalo [0, 1]
	 * como se explica en el cálculo del vector dirección
	 */
	private function get_color():Number {
		// No se puede usar la fórmula esperada:
		// transform.colorTransform.redOffset-punto[i]/direccion[i];, siendo i alguno de {0, 1, 2}
		// porque no contempla el caso de direccion = [0, 0, 0] (división por 0)
		return _color_temp;
	}
}